﻿<?php

/*
 * File:        includes/class/session.class.php
 * Author:      jack@yeahcpa.com
 * Date:        2011-10-09
 * Intro:       利用Session完成cached操作类
 *              该类的测试及示例: test/session.test.php
 */

class YeahTraceSession
{
    //$YeahTraceSessionId用来存储YeahTraceSession类中的公共信息
    //除非特殊需求，请勿修改此值
    //包括：
    //  所有session id
    //  全部session数量
    public static $YeahTraceSessionId = 'YeahTraceSessionId.7e4ccc89-ac99-db8e';

    //$cache_dir用于cache file目录的定义
    public static $cache_dir = '../cache/';

    //$max_record_count用于指定单个session中所缓存数据的最大条数
    public static $max_record_count = 500;

    //$last_active用于记录session最后活动时间
    public $last_active;

    private $session_id;
    private $cache_file;
   
    private $db;
    //初始化session id,COUNT
    //启动session
    //设置session的memcached存储
    function __construct($session_id){
        //设置session为memcache存储
        ini_set('session.save_handler', 'memcache');
        ini_set('session.save_path', 'tcp://localhost:11211');
			 //创建数据库对象
		 $this->db=new   mysql();

        //设置session过期时间为4小时
        session_cache_expire(240);

        session_id($session_id);
        session_start();

        if(!isset($_SESSION['COUNT'])){
            $_SESSION['COUNT'] = 0;
        }
		//session  入库记录
		 $this->NewSession($session_id);
		 
        $this->cache_file = self::$cache_dir . $session_id;
		
        $this->session_id = $session_id;

        $this->last_active = time();
        if(isset($_SESSION['LAST_ACTIVE'])){
            $this->last_active = $_SESSION['LAST_ACTIVE'];
        }
    }

    //方便操作的包装函数
    
    //添加单条信息并释放session
    //可在trace模块中使用该函数
    //注意：使用该函数后会关闭session读写
    //      清勿在使用后再对此对象进行任何操作
    public function AddAndRelease($content){
        $this->Append($content);
        $this->Free();
    }

    //读取某session id中的全部内容，并释放该session id所占用的全部资源
    //用于分析模块
    //注意：使用该函数后会关闭session读写
    //      清勿在使用后再对此对象进行任何操作
    public function ReadAndDel(){
        $content = $this->ReadContentInAll(TRUE);
		
         $this->Free();
		 
         $this->ReleaseSession($session_id);
		 
         return $content;
    }

    //以当前的microtime作为key，向session中追加一条内容
    //
    //参数:
    //  $content:需要添加内容的字符串
    //返回值:
    //  true:成功写入
    //  false:写入失败，同一时间多次写入
    public function Append($content){
        $session_key = strval(microtime(true));

        if(isset($_SESSION[$session_key])){
            return false;
        }

        $_SESSION[$session_key] = $content;
        ++$_SESSION['COUNT'];

        //更新最后写入时间
        $_SESSION['LAST_ACTIVE'] = time();

        //检查是否超过容量限制
        if($_SESSION['COUNT'] >= self::$max_record_count){
            $this->Cache2File();
        }

        return true;
    }

    //将Session内容写入文件
    //释放memcached容量
    public function Cache2File(){
        //cache文件由cache路径＋session id共同组成
        $file_path = $this->cache_file;
        $file_handle = fopen($file_path, 'a');

        if(!$file_handle){
            echo $file_path . ' open error';
        }

        $content = $this->ReadContentInSession(TRUE);

        foreach($content as $key => $value){
            fwrite($file_handle, $key . '|' . $value . "\n");
        }

        fclose($file_handle);
    }

    //查询session中已有数据条数
    public function RecordCountInSession(){
        return $_SESSION['COUNT'];
    }

    //查询cache file中数据条数
    public function RecordCountInFile(){
        $file_path = $this->cache_file;

        $file_handle = fopen($file_path, 'r');
        $file_line_count = 0;

        //无缓存文件时返回0
        if(!file_exists($file_path)){
            return $file_line_count;
        }

        //查询记录行数,每行字符上限9999
        while(!feof($file_handle)){
            if(fgets($file_handle, 9999)){
                ++$file_line_count;
            }
        }

        fclose($file_handle);

        return $file_line_count;
    }

    //查询该session id中已有数据条数(包括缓存文件)
    public function RecordCountInAll(){
        return $this->RecordCountInSession() + $this->RecordCountInFile();
    }

    //读取(并删除)session中的内容
    public function ReadContentInSession($del = FALSE){
        $content = array();

        foreach($_SESSION as $key => $value){
            if($key == strval(floatval($key))){
                $content[$key] = $value;
                //根据设置判断是否从session中删除所读出的数据
                if($del){
                    unset($_SESSION[$key]);
                    -- $_SESSION['COUNT'];
                }
            }
        }

        return $content;
    }

    //读取(并删除)cache file中的内容
    public function ReadContentInFile($del = FALSE){

        $content = array();

        $file_path = $this->cache_file;
		    //无缓存文件时返回''
        if(!file_exists($file_path)){
            return $content;
        }
        $file_handle = fopen($file_path, 'r');

    

        while(!feof($file_handle)){
            if($line_content = fgets($file_handle, 9999)){
                list($key, $value) = explode('|', $line_content, 2);
                if($key && $value){
                    $content[$key] = $value;
                }
            }
        }

        fclose($file_handle);

        if($del){
            unlink($file_path);
        }

        return $content;
    }

    //读取(并删除)session id中全部的内容
    public function ReadContentInAll($del = FALSE){
        $session_content = $this->ReadContentInSession($del);
        $file_content = $this->ReadContentInFile($del);

        return $session_content + $file_content;
    }

    //释放session锁
    public function Free(){
        session_write_close();
    }

    /*
     * 利用数据库实现session列表
     * 并利用该列表和轮询程序进行分析检测
     * 数据表应有：
     *  session_count:记录现有session数量
     *  session_id:session id
     *  create_time:创建时间
     */

    //在Session列表中新增一个session记录
    private function NewSession($session_id){
  
        //增加session_id/create_time
		$session_arr = array(
		"table"		=>	"session",
		"field"     => "trace_session_count",
		"where"		=>	"trace_sessionname='".$session_id."'");
		
	$query = $this->db->select($session_arr);

	if($row=$this->db->fetch_array($query))
	{
	//如果此sessionid存在则 session_count+1
	$data=array(
	'trace_session_count'=>$row['trace_session_count']+1,
	);
	
	$this->db->update($data,array("table"=>"session","where"=>"trace_sessionname='$session_id'"));
	}
	else 
	{

	//如果此sessioni不存在   则session入库进行记记录
	$data=array(
	'trace_sessionname'=>$session_id,
	'trace_session_count'=>1,
	'trace_create_time'=>time()
	);
	
    $this->db->insert($data, array("table"=>"session"));
	
    }

       $this->db->free_result($query);
        //递增session_count
    }

    //在Session列表中增加一个session
    private function ReleaseSession($session_id){
        //删除session_id/create_time
		
		$datas= array(
		"table"		=>	"session",
		"where"		=>	"trace_sessionname='".$session_id."'");
		
		
		 $this->db->delete($datas);
		 
		
        //递减session_count
    }
}

class YeahTraceMemcache
{
    private $mem;
    private $stats;

    function __construct(){
        $this->mem = new Memcache();
        $this->mem->connect('localhost', 11211) or die('memcache down');

        $this->stats = $this->mem->getStats();
    }

    //服务器负载，返回float数据,1表示满载.0表示空载
    public function Load(){

        if(!$this->this->stats){
            return FALSE;
        }

        $limit_maxbytes = $this->stats['limit_maxbytes']; //最大内存
        $bytes = $this->stats['bytes'];   //可用内存

        return floatval($bytes / $limit_maxbytes);
    }

}

?>
